package canglang.monitor.core.codelookup.taglib;

import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
import org.springframework.context.ApplicationContext;
import static org.springframework.web.context.support.WebApplicationContextUtils.getWebApplicationContext;

import javax.servlet.jsp.tagext.TagSupport;
import javax.servlet.jsp.JspException;
import java.util.*;

import canglang.monitor.core.codelookup.service.CodeLookupMgr;
import canglang.monitor.core.codelookup.model.CodeModel;

@SuppressWarnings("unchecked")
public class CollectionTag extends TagSupport {

    /**
     * Delimiter for filterParams attribute.
     */
    private static final String FILTER_PARAMS_DELIMITER = ",";

    /**
     * The code-type in codelookup-config.xml.
     */
    private String codeType;

    /**
     * "ture" means only return active code list.
     * This will be ignored if filterName is not empty and
     * return only the active code list.
     */
    private String activeOnly;

    /**
     * Inculde this code id in the returned list.
     */
    private String includeCodeId;

    /**
     * Prepend code id.
     */
    private String prependCodeId;

    /**
     * Prepend code desc.
     */
    private String prependCodeDesc;

    /**
     * The sql-filter name in codelookup-config.xml.
     */
    private String filterName;

    /**
     * One or more filter params.  Use "," as delimiter.
     * eg. "Code1,Code2"
     */
    private String filterParams;

    /**
     * Lookup from codelookup-config.properties instead of from database
     * if this parameter is set to 'true'.
     */
    private String lookupFromFile;

    /**
     * Sorting attribute of the <code>CodeTO</code>.  For example "codeDesc"
     */
    private String sortingField;

    /**
     * Sorting order.  A - for ascending, D - for descending, default = ascending
     */
    private String sortingOrder;

    public String getCodeType() {
        return codeType;
    }

    public void setCodeType(String codeType) throws JspException {
        this.codeType = codeType;
    }

    public String getActiveOnly() {
        return activeOnly;
    }

    public void setActiveOnly(String activeOnly) {
        this.activeOnly = activeOnly;
    }

    public String getIncludeCodeId() {
        return includeCodeId;
    }

    public void setIncludeCodeId(String includeCodeId) {
        this.includeCodeId = includeCodeId;
    }

    public String getPrependCodeId() {
        return prependCodeId;
    }

    public void setPrependCodeId(String prependCodeId) {
        this.prependCodeId = prependCodeId;
    }

    public String getPrependCodeDesc() {
        return prependCodeDesc;
    }

    public void setPrependCodeDesc(String prependCodeDesc) {
        this.prependCodeDesc = prependCodeDesc;
    }

    public String getFilterName() {
        return filterName;
    }

    public void setFilterName(String filterName) {
        this.filterName = filterName;
    }

    public String getFilterParams() {
        return filterParams;
    }

    public void setFilterParams(String filterParams) {
        this.filterParams = filterParams;
    }

    public String getLookupFromFile() {
        return lookupFromFile;
    }

    public void setLookupFromFile(String lookupFromFile) {
        this.lookupFromFile = lookupFromFile;
    }

    public String getSortingField() {
        return sortingField;
    }

    public void setSortingField(String sortingField) {
        this.sortingField = sortingField;
    }

    public String getSortingOrder() {
        return sortingOrder;
    }

    public void setSortingOrder(String sortingOrder) {
        this.sortingOrder = sortingOrder;
    }

    public int doEndTag() throws JspException {
        // Evaluate EL Expression

        if (codeType != null) {
            codeType = (String) ExpressionEvaluatorManager.evaluate("codeType", codeType, String.class, this, pageContext);
        }

        if (activeOnly != null) {
            activeOnly = (String) ExpressionEvaluatorManager.evaluate("activeOnly", activeOnly, String.class, this, pageContext);
        }

        if (includeCodeId != null) {
            includeCodeId = (String) ExpressionEvaluatorManager.evaluate("includeCodeId", includeCodeId, String.class, this, pageContext);
        }

        if (prependCodeId != null) {
            prependCodeId = (String) ExpressionEvaluatorManager.evaluate("prependCodeId", prependCodeId, String.class, this, pageContext);
        }

        if (prependCodeDesc != null) {
            prependCodeDesc = (String) ExpressionEvaluatorManager.evaluate("prependCodeDesc", prependCodeDesc, String.class, this, pageContext);
        }

        if (filterName != null) {
            filterName = (String) ExpressionEvaluatorManager.evaluate("filterName", filterName, String.class, this, pageContext);
        }

        if (filterParams != null) {
            filterParams = (String) ExpressionEvaluatorManager.evaluate("filterParams", filterParams, String.class, this, pageContext);
        }

        if (lookupFromFile != null) {
            lookupFromFile = (String) ExpressionEvaluatorManager.evaluate("lookupFromFile", lookupFromFile, String.class, this, pageContext);
        }


        List codeList;
        ApplicationContext context = getWebApplicationContext(this.pageContext.getServletContext());
        CodeLookupMgr codeLookupManager = (CodeLookupMgr) context.getBean("codeLookupManager");
            if (useFilter()) {
                codeList = codeLookupManager.getCodeList(codeType, filterName, getFilterParamsList());
            } else {
                codeList = codeLookupManager.getCodeList(codeType);
            }

            if (this.sortingField != null) {
                if (this.sortingOrder != null) {
                    Collections.sort(codeList, new CodeComparator(this.sortingField, this.sortingOrder));
                } else {
                    Collections.sort(codeList, new CodeComparator(this.sortingField, "A"));
                }
            }

            pageContext.setAttribute(id, codeList);
            return EVAL_PAGE;
        }

    /**
     * Get a <code>List</code> of filer params using <code>filterParams</code>
     * attribute and <code>FILTER_PARAMS_DELIMITER</code> as delimiter.
     *
     * @return filter params in a <code>List</code>.
     */
    private List getFilterParamsList() {
        List paramsList = new ArrayList();
        if (filterParams != null && !filterParams.equals("")) {
            StringTokenizer token = new StringTokenizer(filterParams,
                    FILTER_PARAMS_DELIMITER);
            while (token.hasMoreTokens()) {
                paramsList.add(token.nextToken());
            }
        }
        return paramsList;
    }

    /**
     * If no filter name then return false else return true.
     *
     * @return ture if use filter otherwise false.
     */
    private boolean useFilter() {
        return !(filterName == null || filterName.equals(""));
    }
}

class CodeComparator implements Comparator {
    private String sortingField;
    private String sortingOrder;

    public CodeComparator(String sortingField, String sortingOrder) {
        this.sortingField = sortingField;
        this.sortingOrder = sortingOrder;
    }

    public int compare(Object obj1, Object obj2) {
        CodeModel codeTO1 = (CodeModel) obj1;
        CodeModel codeTO2 = (CodeModel) obj2;

        if ("codeDesc".equals(sortingField)) {
            if ("D".equals(sortingOrder)) {
                if (codeTO1.getCodeDesc().compareTo(codeTO2.getCodeDesc()) > 0) {
                    return -1;
                } else {
                    return 1;
                }
            } else {
                if (codeTO1.getCodeDesc().compareTo(codeTO2.getCodeDesc()) > 0) {
                    return 1;
                } else {
                    return -1;
                }
            }
        }

        return 0;
    }
}